package com.prince.util;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * 字符串 DESede(3DES) 加密
 */
public class Base3DES {
	private static final String Algorithm = "DESede"; // 定义 加密算法,可用 DES,DESede,Blowfish
	private static final String hexString = "ABCDEF0123456789";

	/**
	 * 
	 * @param keybyte
	 *            加密密钥，长度为24字节
	 * @param src
	 *            字节数组(根据给定的字节数组构造一个密钥。 )
	 * @return
	 */
	public static byte[] encryptMode(byte[] keybyte, byte[] src) {
		try {
			// 根据给定的字节数组和算法构造一个密钥
			SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
			// 加密
			Cipher c1 = Cipher.getInstance(Algorithm);
			c1.init(Cipher.ENCRYPT_MODE, deskey);
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	public static String encrypt3DES(String value, String key) {
		String str = null;
		try {
			str = byte2Base64(encryptMode(key.getBytes(), value.getBytes("UTF-8")));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return str;
	}
	/**
	 *3des 解密 （解密对应encrypt3DES方法的字符串）
	 * @param value 需要解密的数据
	 * @param key 密钥
	 * @return
	 */
	public static String decrypt3DES(String value, String key) {
		byte[] decrypt = null;
		try {
			byte[] decode = Base64.decode(value);
			decrypt = Base3DES.decryptMode(key.getBytes(),decode);
		}catch (Exception e) {
			e.printStackTrace();
		}
		if(decrypt == null) {
			return null;
		}
		value = new String(decrypt);
		return value;
	}
	public static String byte2Base64(byte[] b) {
		return Base64.encode(b);  
	}
	/**
	 * 
	 * @param keybyte
	 *            密钥
	 * @param src
	 *            需要解密的数据
	 * @return
	 */
	public static byte[] decryptMode(byte[] keybyte, byte[] src) {
		try {
			// 生成密钥
			SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
			// 解密
			Cipher c1 = Cipher.getInstance(Algorithm);
			c1.init(Cipher.DECRYPT_MODE, deskey);
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * encrypt data by 3des
	 * 
	 * @param key
	 * @param src
	 * @return
	 */
	public static byte[] encryptData(byte[] key, byte[] src) {
		try {
			// 生成密钥
			SecretKey deskey = new SecretKeySpec(key, Algorithm);
			System.out.println("deskey = " + deskey);
			// 加密
			Cipher c1 = Cipher.getInstance(Algorithm + "/ECB/NoPadding");
			c1.init(Cipher.ENCRYPT_MODE, deskey);
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * 3DES加密数据
	 * 
	 * @param keyStr
	 * @param srcStr
	 * @return
	 */
	public static String encryptData(String keyStr, String srcStr) {
		try {
			byte[] key = hex2byte(keyStr);
			byte[] src = srcStr.getBytes("UTF-8"); // 需要对源数据进行补齐
			int len = src.length;
			int paddingLen = len % 8; // 补齐为8的整数倍

			byte[] srcPad = new byte[len + (8 - paddingLen)];
			Arrays.fill(srcPad, (byte) 0x0); // 补齐内容为0x0

			System.arraycopy(src, 0, srcPad, 0, len); // 将加密数据拷贝到加密数组中

			byte[] result = encryptData(key, srcPad);
			return byte2hex(result);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 反格式化byte[压缩字符串]s的长度必须是偶数
	 * 
	 * @param s
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static byte[] hex2byte(String s) throws UnsupportedEncodingException {
		byte[] src = s.toLowerCase().getBytes("UTF-8");
		byte[] ret = new byte[src.length / 2];
		for (int i = 0; i < src.length; i += 2) {
			byte hi = src[i];
			byte low = src[i + 1];
			hi = (byte) ((hi >= 'a' && hi <= 'f') ? 0x0a + (hi - 'a') : hi - '0');
			low = (byte) ((low >= 'a' && low <= 'f') ? 0x0a + (low - 'a') : low - '0');
			ret[i / 2] = (byte) (hi << 4 | low);
		}
		return ret;
	}

	/**
	 * 字符串转为16进制
	 * 
	 * @param str
	 * @return
	 */
	public static String encode(String str) {
		// 根据默认编码获取字节数组
		byte[] bytes = str.getBytes();
		StringBuilder sb = new StringBuilder(bytes.length * 2);

		// 将字节数组中每个字节拆解成2位16进制整数
		for (int i = 0; i < bytes.length; i++) {
			sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
			sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
		}
		return sb.toString();
	}

	/**
	 * 
	 * @param bytes
	 * @return 将16进制数字解码成字符串,适用于所有字符（包括中文）
	 */
	public static String decode(String bytes) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
		// 将每2位16进制整数组装成一个字节
		for (int i = 0; i < bytes.length(); i += 2) {
			baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));
		}
		return new String(baos.toByteArray());
	}

	// 转换成十六进制字符串
	public static String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			}else {
				hs = hs + stmp;
			}
			if (n < b.length - 1) {
				hs = hs + ":";
			}
		}
		return hs.toUpperCase();
	}

	public static void main(String[] args) {
//		// 添加新安全算法,如果用JCE就要把它添加进去
//		// 这里addProvider方法是增加一个新的加密算法提供者(个人理解没有找到好的答案,求补充)
//		Security.addProvider(new com.sun.crypto.provider.SunJCE());
//		// byte数组(用来生成密钥的)
//		final byte[] keyBytes = { 0x11, 0x22, 0x4F, 0x58, (byte) 0x88, 0x10, 0x40, 0x38, 0x28, 0x25, 0x79, 0x51,
//				(byte) 0xCB, (byte) 0xDD, 0x55, 0x66, 0x77, 0x29, 0x74, (byte) 0x98, 0x30, 0x40, 0x36, (byte) 0xE2 };
//		String szSrc = "This is a 3DES test. 测试";
//		System.out.println("加密前的字符串:" + szSrc);
//
//		byte[] encoded = encryptMode(keyBytes, szSrc.getBytes());
//		System.out.println("加密后的字符串:" + new String(encoded));
//
//		byte[] srcBytes = decryptMode(keyBytes, encoded);
//		System.out.println("解密后的字符串:" + new String(srcBytes));
//		// ------------------------------------------------------------
//		String byt = "系娄系甘早阵庸迸在蛋弄胶瓶帖孔";
//		byt = encode(byt);
//		System.out.println(byt);
//		byt = decode(byt);
//		System.out.println(byt);
//
//		// E5AD97E7ACA6E4B8B2E8BDACE68DA2E4B8BA3136E8BF9BE588B6
		String byt = "旅游转16进制";
		System.out.println(encode(byt));
	}
}
